﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using System.Windows.Controls.Primitives;
using Odyssey.Utils;
using System.Linq;
using Microsoft.Phone.Shell;
using System.Windows.Data;
using System.Windows.Threading;

namespace Odyssey.Controls
{
    /// <summary>
    /// Button control which opens a overlay over the current page when tapped.
    /// </summary>
    public class PickerBox : CommandButton
    {

        public PickerBox()
            : base()
        {
            base.DefaultStyleKey = typeof(PickerBox);
        }


        private Overlay overlay;

        protected Overlay Overlay { get { return overlay; } }

        /// <summary>
        /// Gets or sets the delay to wait until closing the overlay when an item was selected.
        /// If set to a value>0, it gives an amimation time to execute before the overlay is being closed.
        /// </summary>
        public TimeSpan CloseDelay
        {
            get { return (TimeSpan)GetValue(CloseDelayProperty); }
            set { SetValue(CloseDelayProperty, value); }
        }

        public static readonly DependencyProperty CloseDelayProperty =
            DependencyProperty.Register("CloseDelay", typeof(TimeSpan), typeof(ListPicker), new PropertyMetadata(TimeSpan.FromMilliseconds(0.0)));

        public object SelectedItem
        {
            get { return (object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }


        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(object), typeof(PickerBox), new PropertyMetadata(null, OnSelectedItemChanged));

        private static void OnSelectedItemChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            (o as PickerBox).OnSelectedItemChanged(args.OldValue, args.NewValue);
        }

        protected virtual void OnSelectedItemChanged(object oldValue, object newValue)
        {
            Content = SelectedItem;
        }

        public ApplicationBar ApplicationBar
        {
            get { return (ApplicationBar)GetValue(ApplicationBarProperty); }
            set { SetValue(ApplicationBarProperty, value); }
        }

        public static readonly DependencyProperty ApplicationBarProperty =
            DependencyProperty.Register("ApplicationBar", typeof(ApplicationBar), typeof(PickerBox), new PropertyMetadata(null));

        public object OverlayContent
        {
            get { return (object)GetValue(PopupContentProperty); }
            set { SetValue(PopupContentProperty, value); }
        }

        public static readonly DependencyProperty PopupContentProperty =
            DependencyProperty.Register("OverlayContent", typeof(object), typeof(PickerBox), new PropertyMetadata(null));


        /// <summary>
        /// Gets or sets the DataTemplate for the Overlay control which appears when opened.
        /// </summary>
        public DataTemplate OverlayTemplate
        {
            get { return (DataTemplate)GetValue(OverlayTemplateProperty); }
            set { SetValue(OverlayTemplateProperty, value); }
        }

        public static readonly DependencyProperty OverlayTemplateProperty =
            DependencyProperty.Register("OverlayTemplate", typeof(DataTemplate), typeof(PickerBox), new PropertyMetadata(null));

        public ControlTemplate OverlayContainerTemplate
        {
            get { return (ControlTemplate)GetValue(PopupTemplateProperty); }
            set { SetValue(PopupTemplateProperty, value); }
        }

        public static readonly DependencyProperty PopupTemplateProperty =
            DependencyProperty.Register("OverlayContainerTemplate", typeof(ControlTemplate), typeof(PickerBox), new PropertyMetadata(null));

        public bool IsOpen
        {
            get { return (bool)GetValue(IsOpenProperty); }
            set { SetValue(IsOpenProperty, value); }
        }

        public static readonly DependencyProperty IsOpenProperty =
            DependencyProperty.Register("IsOpen", typeof(bool), typeof(PickerBox), new PropertyMetadata(false, OnOpenChanged));

        private static void OnOpenChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            bool newValue = (bool)args.NewValue;
            (o as PickerBox).OnOpenChanged(!newValue, newValue);
        }

        protected virtual void OnOpenChanged(bool oldValue, bool newValue)
        {
            if (newValue) Open(); else Close();
        }

        protected override void OnClick()
        {
            base.OnClick();
            IsOpen = true;
        }

        protected virtual void Open()
        {
            OnOpening();

            overlay = new Overlay(this)
            {
                ContentTemplate = OverlayTemplate,
                CloseDelay = this.CloseDelay,
                ApplicationBar = this.ApplicationBar
            };

            BindOverlayContent(overlay);

            var template = OverlayContainerTemplate;
            if (template != null) overlay.Template = template;

            overlay.Closing += (s, e) => OnClosing(overlay);
            overlay.Opened += (s, e) => OnOpened();
            overlay.Closed += (s, e) => OnClosed();

            overlay.IsOpen = true;
        }


        protected virtual void BindOverlayContent(Overlay overlay)
        {
            overlay.SetBinding(Overlay.ContentProperty, new Binding("SelectedItem") { Source = this, Mode = BindingMode.TwoWay });
        }

        protected virtual void Close()
        {
            overlay.IsOpen = false;
        }

        protected ApplicationBarIconButton GetAppBarButton(int index)
        {
            var bar = ApplicationBar;
            if (bar == null) throw new ArgumentNullException("ApplicationBar");
            if (index < 0 || index >= bar.Buttons.Count) throw new ArgumentOutOfRangeException("index");

            return bar.Buttons[index] as ApplicationBarIconButton;
        }

        /// <summary>
        /// Occurs when IsOpen is set to true before the Opened transition after the Overlay completes.
        /// </summary>
        protected virtual void OnOpened()
        {
            var eh = Opened;
            if (eh != null) eh(this, EventArgs.Empty);
        }

        /// <summary>
        /// Occurs when IsOpen was set to false after the Closed transition of the Overlay completes.
        /// </summary>
        protected virtual void OnClosed()
        {
            IsOpen = false;
            overlay.Content = null;
            overlay = null;

            var eh = Closed;
            if (eh != null) eh(this, EventArgs.Empty);
            this.Focus();
        }

        /// <summary>
        /// Occurs when IsOpen is set to false before the Closed transition  over the Overlay completes.
        /// </summary>
        protected virtual void OnClosing(Overlay overlay)
        {
            var eh = Closing;
            if (eh != null) eh(this, EventArgs.Empty);
        }

        /// <summary>
        /// Occurs when IsOpen is set to true before the Opened transition of the Overlay completes.
        /// </summary>
        protected virtual void OnOpening()
        {
            var eh = Opening;
            if (eh != null) eh(this, EventArgs.Empty);
        }

        /// <summary>
        /// Occurs when IsOpen is set to true before the Opened transition after the Overlay completes.
        /// </summary>
        public event EventHandler Opened;

        /// <summary>
        /// Occurs when IsOpen was set to false after the Closed transition of the Overlay completes.
        /// </summary>
        public event EventHandler Closed;

        /// <summary>
        /// Occurs when IsOpen is set to true before the Opened transition of the Overlay completes.
        /// </summary>
        public event EventHandler Opening;

        /// <summary>
        /// Occurs when IsOpen is set to false before the Closed transition  over the Overlay completes.
        /// </summary>
        public event EventHandler Closing;

    }
}
